Arduino PWM Sound Output – Part 2
https://diyelectromusic.com/2021/08/08/arduino-pwm-sound-output-part-2/
の #機械翻訳
Arduino PWM サウンド出力 – パート 2
前回の記事では、Arduino で PWM を使う理論をすべて解説し、Timer 1 を使ってピン 9 で PWM 出力を生成する例を示しました。
今回の記事では、Timer 2 を使ってピン 3 でオーディオ信号を生成できる、別の PWM ルーチン一式を提供します。
本プロジェクトで使う主要な Arduino チュートリアル:
Arduino Foundations PWM
Sparkfun “What is Pulse-width Modulation”
Secrets of Arduino PWM
PWM DAC
Working with Atmel AVR Microcontroller Basic Pulse Width Modulation (PWM) Peripheral
Arduino を初めて使う方は、「Getting Started」ページをご覧ください。
部品リスト
Arduino Uno
10 kΩ ポテンショメータ
220 Ω 抵抗 ×1 と 8 Ω スピーカー、または古いヘッドフォンのスピーカーユニット
(オプション)Arduino PWM Output Filter Circuit
ブレッドボードとジャンパーワイヤ
(オプション)出力を観測するためのオシロスコープ
https://gyazo.com/53afd03688e390f22255ffb476326c7a
これは前回と同じ回路ですが、音声出力がピン 3 から行われる点が異なります。そのため、ピン 3 を出力機器(スピーカー+抵抗、または出力回路)に接続し、リターン(GND)を Arduino の GND に接続してください。
今回も Arduino PWM 出力フィルター回路を使い、小型のポータブルアンプとスピーカーに接続しています。
コード
このコードの背景にある理論については「Arduino PWM Sound Output」をご覧ください。
この例では、Timer 1 の設定を Timer 2 に再現しようと試みましたが、問題があります。Timer 2 は 8 ビットタイマーなのでカウンタ値は最大 255 までしか扱えません。つまり、以前と同じようにカウンタ値 487 を使った FastPWM モードを利用できません。そこで次の二択になります:
PWM 周波数を 65 536 Hz に倍増し、カウンタ値を 243 にする
PWM Phase Correct モードを使う(このモードはカウントが一度上がってから戻るので、カウンタ値 244 で 32 768 Hz の PWM 周波数になる)
最初は Phase Correct モードを試しましたが、波形の途中に奇妙な“無音”区間が出てしまいました。アキュムレータは正常にカウントし、ウェーブテーブルからも正しい値を取り出しているように見えるのですが、なぜかその区間だけ音が出ません。
Phase Correct モードでは割り込みがサイクルの下端(0 カウント)で発生するため、FastPWM の上端(TOP カウント)で起きる場合と違いがあるのかもしれません。OC2A 比較マッチで割り込みをかけるようにも試しましたが、挙動は変わりませんでした。
また、サンプリングレートと PWM 周波数が同じ場合、位相ずれのような何かが起きているのではないかという疑問もありました。
最終的に私は、PWM モードを FastPWM(65 536 Hz)に戻し、サンプルレートはそのまま、割り込みが来るたびではなく「隔回」でサンプル出力する方式にしました。こうすれば、たとえ位相ずれがあっても、サンプル1回に対し少なくとも PWM サイクルが1回は挟まるはずです。
現在使用している設定は以下のとおりです:
サンプル周波数:32 768 Hz
PWM 周波数:65 536 Hz
Timer 2 を FastPWM モード、プリスケーラなし、OCR2A を TOP 値として 243 に設定
Timer 2 オーバーフロー割り込みでサンプル出力ルーチンを実行
OCR2B を比較マッチ出力先に設定し、OC2B(Uno のピン 3)が PWM 出力になるように使用
setup() 内で先に計算しておいた長さ 256 のウェーブテーブルを使用
A0 に接続したポテンショメータで、読み値 0 ~ 1023 を周波数 220Hz ~ 1243Hz にマッピング
この設定によるオーディオ特性は:
サンプルレート:32 768 Hz
PWM 振幅(ピーク・ツー・ピーク):0 ~ 244
DC オフセット(バイアス):122
ウェーブテーブル値:0 ~ 255
この方式で問題なく動作しています。
下の写真は、まずテスト用の 25% デューティー比 PWM 波(65 536 Hz)を表示し、その後フィルターを通した 220Hz の正弦波を捉えたものです。
https://gyazo.com/effcea19d1421d580f73880e765d4761https://gyazo.com/93e42c867e1a306f559f7dd0b3928eee
コードが更新され、Timer 2 を使用してピン 3 から出力するビルドオプションが追加されました。
GitHub でソースはこちらからご覧いただけます。
締めくくりの考察
いずれ「対応可能なすべてのピンでオーディオ PWM を扱える」ようなライブラリを作れたら素敵だと思います。そういったライブラリがすでに存在するのかは分かりませんが、これまでの調査では見かけていません。
上記や前回の記事で誤りや誤解があれば、ぜひお知らせください。また、Uno 上での PWM オーディオ向け汎用コードなど、ご存知でしたらご教示いただけると嬉しいです!
— Kevin